module Practica1 where

import PrePractica
import List
import Maybe 

-- Ejercicio 1

max2 (x,y)  | x >= y = x
            | otherwise = y

normaVectorial (x,y) = sqrt (x^2+y^2)

substract = flip (-)

restarUno = substract 1

evaluarEnCero = \ f -> f 0

dosVeces = \f->f.f

flipAll = map flip

{-
max2 :: Ord a => (a,a) -> a
normaVectorial :: Floating a => (a,a) -> a
substract :: Integer -> Integer -> Integer
restarUno :: Integer -> Integer
evaluarEnCero :: (Integer -> a) -> a
dosVeces :: (a -> a) -> a -> a
flipAll :: [a -> b -> c] -> [b -> a -> c]

Las dos primeras no están currificadas
max2c :: Ord a => a -> a -> a
normaVectorialc :: Floating a => a -> a -> a
-}

max2c x y   | x >= y = x
            | otherwise = y
 
normaVectorialc x y = sqrt (x^2+y^2)

-- ejercicio 2 - I
-- no entiendo una goma
curry f (x,y) = \ f (x, y) -> f x y





-- ejercicio 3
ejtres = [x | x <- [1..2], y <- [x..3], (x+y) `mod` 2 == 0]
-- resulta [1, 1, 2] ya que (1+1) (1+3) y (2+2) son pares.

-- ejercicio 4
pitagoricas :: [(Integer,Integer,Integer)]
-- pitagoricas = [(a,b,c) | a <- [1..], b <-[1..], c <- [1..], a^2 + b^2 == c^2] no termina nunca ni encuentra nada
pitagoricas = [(a, b, c) | c <- [1..], b <-[1..c], a<-[1..c], (a^2 + b^2 == c^2)]


-- ejercicio 5
milPrimos = take 1000 [x | x <- [1..], primo x]

-- ejercicio 6
partir :: [a] -> [([a], [a])]
partir xs = partirAux (length xs) xs

partirAux :: Int -> [a] -> [([a], [a])]
partirAux 0 xs = [([], xs)]
partirAux n xs = (partirAux (n-1) xs) ++ [((take n xs), (drop n xs))]

partir2 :: [a] -> [([a], [a])]
partir2 xs = foldr (\ x rec -> ((take (snd x) (fst x)), (drop (snd x) (fst x))):rec) [] ([(xs, x) | x<-[0..(length xs)]])

-- ejercicio 7
listasQueSuman::Int->[[Int]]
listasQueSuman 0 = [[]]
listasQueSuman n | n > 0 = [(x:xs) | x<-[1..n], xs<-listasQueSuman (n-x)]

-- ejercicio 8
todasLasListasFinitas :: [[Int]]
todasLasListasFinitas = aplanar [listasQueSuman x | x<-[1..4]]

aplanar :: [[a]] -> [a]
aplanar xss = foldr (\xs rec -> xs++rec) [] xss

-- ejercicio 9
sumFR :: Num a => [a] -> a
sumFR = foldr (\x rec -> x+rec) 0

elemFR :: Eq a => a -> [a] -> Bool
elemFR e = foldr (\x rec -> x==e || rec) False 

masmas :: [a] -> [a] -> [a]
masmas xs ys = foldr (\x rec -> x:rec) ys xs -- (\x ys -> ys)

filterFR :: (a -> Bool) -> [a] -> [a]
filterFR f = foldr (\ x rec -> if f x then x:rec else rec ) []

mapFR :: (a->b) -> [a] -> [b]
mapFR f = foldr (\x rec -> (f x):rec) []

sumaAlt :: Num a => [a] -> a
--sumaAlt xs = fst (foldr (\x rec -> ((snd rec)*x+(fst rec), (-1)*snd rec)) (0,-1) xs)
sumaAlt xs = foldr (\(x,s) rec -> (s*x+rec)) 0
        (zip xs [if (mod x 2)==0 then -1 else 1 | x<-[1..]])

sumaAltR :: Num a => [a] -> a
sumaAltR xs = fst (foldr (\x rec -> ((snd rec)*x+(fst rec), (-1)*snd rec)) (0,-1) xs)

-- ejercicio 10
partes :: [a] -> [[a]]
partes = foldr (\x rec -> rec++(map (x:) rec)) [[]]

prefijos :: [a] -> [[a]]
prefijos xs = foldr (\x rec -> (init (head rec)):rec) [xs] xs

sufijos :: [a] -> [[a]]
sufijos xs = foldr (\x rec -> (tail (head rec)):rec) [xs] xs

sublistas :: [a] -> [[a]]
--sublistas xs = foldr (\x rec -> [y | ] ++ rec) [xs] xs
--sublistas xs = []:sacarVacia (aplanar (map prefijos (sufijos xs))) 
sublistas xs = []:sacarVacia (aplanar (map sufijos (prefijos xs))) 

sacarVacia :: [[a]] -> [[a]]
sacarVacia = foldr (\x rec -> case x of 
                            [] -> rec 
                            otherwise -> x:rec) []

-- ejercicio 11
sacarUna :: Eq a => a -> [a] -> [a]
sacarUna e xs = (fst s) ++ (if null (snd s) then [] else tail (snd s))
            where s = break (==e) xs

permutaciones :: Eq a => [a] -> [[a]]
permutaciones [] =  [[]]
permutaciones xs = [(x:ys) | x<-xs, ys<- permutaciones (sacarUna x xs)]

-- ejercicio 12
-- genLista 10 3 (+1)
genLista :: Num a => Int -> a -> (a->a) -> [a]
genLista cant init func = take cant (iterate func init)

desdeHasta :: Int -> Int -> [Int]
desdeHasta i f = genLista cant i (+1)
                where cant = f-i+1

-- ejercicio 13
-- take 10 (mapPares (\(x,y) -> x+y) [(z,z) | z<-[1..]])
mapPares :: ((a,b) -> c) -> [(a,b)] -> [c]
mapPares f = foldr (\x rec -> (f x):rec) []

armarPares :: [a] -> [b] -> [(a,b)]
armarPares = foldr  (\ x zipXs lista -> case lista of 
                                [] -> []
                                (y:ys) -> (x,y):(zipXs ys)) 
                    (const [])

mapDoble :: ((a,b) -> c) -> [a] -> [b] -> [c]
mapDoble f xs ys = [(f (xs!!i, ys!!i)) | i<-[0..((length xs) -1)]]

-- ejercicio 14
sumaMat :: [[Int]] -> [[Int]] -> [[Int]]
sumaMat = zipWith (zipWith (+))
--sumaMat m1 m2 = [zipWith (+) (m1!!i) (m2!!i) | i<-[0..((length m1) -1)]]

trasponer :: [[Int]] -> [[Int]]
trasponer xs = [ [((xs!!j)!!i) | j<-[0..((length xs) -1)]] | i<-[0..((length (xs!!0)) -1)]] 

matriz1 :: [[Int]]
matriz1 = [[1,2,3],[3,4,5]]
matriz2 :: [[Int]]
matriz2 = [[3,3,3],[3,0,0]]

-- ejercicio 15
-- generate (\x -> length x > 10) (\y -> sum y+1)
generate :: ([a] -> Bool) -> ([a] -> a) -> [a]
generate stop next = generateFrom stop next []

generateFrom:: ([a] -> Bool) -> ([a] -> a) -> [a] -> [a]
generateFrom stop next xs   | stop xs = xs
                            | otherwise = generateFrom stop next (xs ++ [next xs])

--generateMaybe (\xs->if (length xs) < 3 then Just 1 else Nothing)
generateMaybe :: ([a] -> Maybe a) -> [a]
generateMaybe f = generate (isNothing . f) (fromJust . f) 

iterateN :: Int ->(a ->a) ->a ->[a]
iterateN  l f i = generate (\xs -> length xs >= l) (\xs -> case xs of 
                                                            [] -> i
                                                            otherwise -> f (last xs))

-- ejercicio 16

-- ejercicio 17
foldNat :: b -> (b -> b) -> Integer -> b
foldNat base _ 0 = base
foldNat base f n = f (foldNat base f (n-1))

potencia :: Integer -> Integer -> Integer
potencia b  = foldNat 1 (\x -> b*x) 

-- ejercicio 18
data Num a=>Polinomio a = X
                        | Cte a
                        | Suma (Polinomio a) (Polinomio a)
                        | Prod (Polinomio a) (Polinomio a)

foldPolinomio :: Num a => (c) -> (a->c) -> (c -> c -> c) -> (c -> c -> c) -> Polinomio a -> c
foldPolinomio cX cC cS cP p = case p of
                    X -> cX
                    Cte n -> cC n
                    Suma i d -> cS (rec i) (rec d)
                        where rec = foldPolinomio cX cC cS cP 
                    Prod i d -> cP (rec i) (rec d)
                        where rec = foldPolinomio cX cC cS cP 

evaluar::Num a=>a->Polinomio a->a
evaluar val = foldPolinomio val id (+) (*)

poli1 = Prod (Suma X (Cte 3)) (Suma (Cte 5) X)
-- ejercicio 9
-- ejercicio 9
-- ejercicio 9
-- ejercicio 9
